package snafu.framework.agents;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import snafu.framework.actions.AbstractAction;
import snafu.framework.actions.Intention;
import snafu.framework.actions.IntentionItself;
import snafu.framework.exceptions.SnafuException;
import snafu.framework.senses.Sense;
import snafu.framework.senses.SenseItself;
import snafu.framework.states.StateItself;
import snafu.framework.states.StateView;
import snafu.framework.view.Access;

public class AgentStateItself extends StateItself implements AgentState {
	protected List<IntentionItself<?>> intentions;
	protected Set<SenseItself> senses;
	
	/**
	 * Initiates a new agent state and creates an empty list of intentions.
	 */
	public AgentStateItself() {
		intentions = new ArrayList<IntentionItself<?>>();
		senses = new HashSet<SenseItself>();
	}
	
	/**
	 * Adds the given intention to the list of intentions.
	 * 
	 * @param intention
	 *            the intention to add
	 */
	public void addIntention(IntentionItself<?> intention) {
		intentions.add(intention);
	}
	
	@Override
	public List<Intention<? extends AbstractAction>> getIntentions() {
		List<Intention<?>> newIntentions = new ArrayList<Intention<?>>();
		for (IntentionItself<?> intention : intentions) {
			newIntentions.add(intention);
		}
		return newIntentions;
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public <I extends Intention<?>> I getIntention(Class<I> clazz) {
		// select intentions matching clazz
		List<Intention<?>> selectedIntentions = new ArrayList<Intention<?>>();
		for (Intention<?> intention : getIntentions()) {
			if (intention.getClass().equals(clazz)) {
				selectedIntentions.add(intention);
			}
		}

		// check how many matches were found
		switch (selectedIntentions.size()) {
		case 0:
			return null;
		case 1:
			return (I) selectedIntentions.get(0);
		default:
			throw new SnafuException("found more than one matching intention for " + clazz);
		}
	}

	/**
	 * Sets the given intention as unique. This means that all intention that equal the given
	 * intention are removed from the list of intentions and the given one will be added.
	 * 
	 * @param intention
	 *            the new unique intention
	 */
	public void setIntention(IntentionItself<? extends AbstractAction> intention) {
		removeIntention(intention);
		intentions.add(intention);
	}
	
	/**
	 * Removes the given intention from the list of intentions.
	 * 
	 * @param intention
	 *            the intention to remove
	 */
	public void removeIntention(IntentionItself<? extends AbstractAction> intention) {
		intentions.remove(intention);
	}
	
	public void addSense(SenseItself sense) {
		senses.add(sense);
	}
	
	@Override
	public Set<Sense> getSenses() {
		Set<Sense> newSenses = new HashSet<Sense>();
		for (Sense sense : senses) {
			newSenses.add(sense);
		}
		
		return newSenses;
	}

	@Override
	public StateView createView(Access access) {
		return new AgentStateView(access, this);
	}
	
}
